/*
 * AJAX远程调用，参数是一个JSON对象
 *
 * param url         请求地址，默认空字符串
 * param type        请求方式，可选 get/post，默认 get
 * param data        请求参数，仅在 post 请求时生效，必须是JSON格式
 * param contentType 请求参数的格式，可选 json/qs/file，默认 qs
 * param dataType    响应数据的格式，可选 json/text，默认 json
 * param success     回调函数，函数的第一个参数为响应数据
 * param async       是否开启异步，默认 true
*/
function ajax(params) {

    // 创建AJAX核心对象: 该对象负责与服务器进行通信
    let xhr = new XMLHttpRequest();

    // 处理参数，添加默认值
    let url = params['url'] ? params['url'] : '';
    let type = params['type'] ? params['type'] : 'get';
    let contentType = params['contentType'] ? params['contentType'] : 'qs';
    let dataType = params['dataType'] ? params['dataType'] : 'json';
    let async = params['async'] ? params['async'] : true;

    // 挂载状态监听事件: 该事件在请求状态码发生改变时触发，必须写于 xhr.open() 之前
    xhr.onreadystatechange = () => {
        // 请求已完成，且响应成功，且存在回调函数
        if (xhr.readyState === 4 && xhr.status === 200 && params['success']) {
            // 根据 dataType 判断是否需要解析响应数据
            let resp = 'text' === dataType ? xhr.responseText : JSON.parse(xhr.responseText);
            // 执行回调函数
            params['success'](resp);
        }
    }

    // 建立异步通道: 参数分别为请求类型，请求地址以及是否开启异步
    xhr.open(type, url, async);

    // 若请求类型为GET
    if ('get' === type) {
        // 发送GET请求，请求参数直接在URL后面附加查询串即可
        xhr.send();
    }
    // 若请求类型为POST
    else {
        // 表单数据，对应后台 `@RequestParam` 注解 + 简单类型参数
        if ('qs' === contentType) {
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
            xhr.send(jsonToQs(params['data']));
        }
        // JSON数据，对应后台 `@RequestBody` 注解 + 实体类型参数
        else if ('json' === contentType) {
            xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8')
            xhr.send(jsonToStr(params['data']));
        }
        // 二进制数据，对应后台 `@RequestParam` 注解 + MultipartFile类型参数
        else if ('file' === contentType) {
            xhr.send(jsonToFormData(params['data']));
        }
    }
}

/*将JSON数据转为QS字符串*/
function jsonToQs(json) {
    return Object.keys(json).map(key => {
        if (Array.isArray(json[key])) {
            return json[key].map(e => key + '=' + e).join('&');
        }
        return key + '=' + json[key]
    }).join('&');
}

/*将JSON数据转为JSON字符串*/
function jsonToStr(json) {
    return JSON.stringify(json);
}

/*将JSON数据转为FormData*/
function jsonToFormData(json) {
    const formData = new FormData();
    Object.keys(json).map(key => {
        formData.append(key, json[key]);
    });
    return formData;
}